import com.pbking.util.eventHandling.EventBroadcaster;
import com.pbking.util.ButterTweenEvent;

/**
 * A Better Tween that's smoothe like Butter (not Peanut Butter, just regular Butter)
 * 
 * Multiple properties can be added to this and animated on the same tween.
 * 
 * The tween works by calling the "update" function every n milliseconds 
 * (defined by setting the interval time at construction)
 * and calculating the delta and applyting it to the properties that are being animated
 * This makes the animation framerate independant.  You can assign a lower interval time
 * for "less important" things.  For instance, "enemy sprites" could use a lower interval time
 * than the "hero" sprite which would create smoother animation at the expense of higher processing
 * needs.
 * 
 * supply an (optional) four property easing function to make the animating all cool and stuff
 * Robert Skinner's functions are perfect for the occaision.  Default is a linear tween.
 * 
 * duration is in milliseconds.  default is 1 second (1000 ms)
 * 
 * Usage:
 * var t:ButterTween = new ButterTween([easingFunction, duration, newIntervalTime]);
 * t.addProperty(target, "property", startValue, endValue); 
 * t.addProperty(target, "property", startValue, endValue);
 * t.addEventListener(ButterTweenEvent.TWEEN_END, this, callbackFunction);
 * t.start(); 
 *  
 * @author jcrist@pbking.com
 */
class com.pbking.util.ButterTween extends EventBroadcaster {
	
	
	public var duration:Number = 1000;	//default is one second;

	private var propList:Array;	//elements in the propList should contain obj, prop, start, delta

	private var intervalID:Number;
	private var INTERVAL_TIME:Number = 25;
	private var func:Function = function (t, b, c, d) { return c*t/d + b; };
	private var currentPosition:Number;
	

	//define type of motion (motion formula) and duration in mSeconds
	function ButterTween (func:Function, duration:Number, newIntervalTime:Number) {
		
		propList = new Array();

		if(duration)this.duration = duration;
		if(newIntervalTime)this.INTERVAL_TIME = newIntervalTime;
		if(func)this.func = func;
	}
	
	//PUBLIC//////////
	
	function addProperty(obj:Object, prop:String, startValue:Number, endValue:Number){
		propList.push({obj:obj, prop:prop, start:startValue, end:endValue, delta:endValue - startValue});
	}
	
	function clearProperties():Void{
		propList.splice(0);
	}
	
	function start(){
		dispatch(new ButterTweenEvent(ButterTweenEvent.TWEEN_BEGIN, this));
		currentPosition = 0;
		//TODO:Calculate interval interval
		this.intervalID = setInterval(this, "updatePosition", INTERVAL_TIME);
	}
	
	function pause(){
		//TODO:Pause
	}
	
	function stop(){
		clearInterval(this.intervalID);
	}
	
	//PRIVATE//////////
	
	private function updatePosition(){
		currentPosition += INTERVAL_TIME;
		if(currentPosition >= duration){
			currentPosition = duration;
			finishProperties();
			clearInterval(this.intervalID);
			dispatch(new ButterTweenEvent(ButterTweenEvent.TWEEN_END, this));
			return;
		}
		updateProperties();
	}
	
	private function updateProperties(){
		for(var i=0; i<propList.length; i++){
			propList[i].obj[propList[i].prop] = func(currentPosition, propList[i].start, propList[i].delta, this.duration);
		}
	}
	
	//make sure they are all at the final values
	private function finishProperties(){
		for(var i=0; i<propList.length; i++){
			propList[i].obj[propList[i].prop] = propList[i].end;
		}
	}
}